package com.vueapi.aspect;

import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import com.alibaba.fastjson.JSONObject;
import com.vueapi.annotation.OperationLog;
import com.vueapi.constant.ErrorCodeEnum;
import com.vueapi.domain.HjOperationLog;
import com.vueapi.exception.TokenException;
import com.vueapi.service.HjOperationLogService;
import com.vueapi.utils.HttpContextUtil;
import com.vueapi.utils.IPUtils;
import com.vueapi.utils.JwtUtil;
import com.vueapi.utils.ResultUtils;
import net.dreamlu.mica.ip2region.core.Ip2regionSearcher;
import net.dreamlu.mica.ip2region.core.IpInfo;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Objects;

/**
 * @Classname LogBlogAspect
 * @Description TODO
 * @Created by 赵宏建
 * @Date 2022/9/20 14:29
 * @Version 1.0.0
 */
@Component
@Aspect
public class OperationLogAspect {

    @Autowired
    private Ip2regionSearcher ip2regionSearcher;

    @Resource
    HjOperationLogService operationLogService;

    @Pointcut("@annotation(com.vueapi.annotation.OperationLog)")
    public void operationLogPoint(){}

    @Around("operationLogPoint()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.currentTimeMillis();
        ResultUtils result = (ResultUtils) pjp.proceed();
        long time = System.currentTimeMillis() - start;

        // 登录时记录用户名称
        String username = "UNKNOWN";

        // 用来记录定时更新的验证
        boolean isController = true;
        if(result == null){
            isController = false;
        }else{
            if(result.getCode() == 4624){
                username = JwtUtil.getUsernameFromToken((String) result.getData());
            }
        }

        recordLog(pjp, time,username,isController);
        return result;
    }

    public void recordLog(ProceedingJoinPoint pjp,long time,String username,boolean isController){
        HjOperationLog log = new HjOperationLog();

        // 记录请求接口、方式、接口名
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        OperationLog annotation = method.getAnnotation(OperationLog.class);

        String className = pjp.getTarget().getClass().getName();
        String methodName = method.getName();

        String operationUrl = className + methodName;
        String operationName = annotation.name();

        if(isController){
            // 获取请求参数
            HttpServletRequest request = HttpContextUtil.getHttpServletRequest();
            String type = request.getMethod();

            if(username.equals("UNKNOWN")){
                String token = request.getHeader("Authorization");
                // 如果 token 为 null，就直接返回
                if(token != null){
                    username = JwtUtil.getUsernameFromToken(token);
                }
            }

            // 记录IP、IP来源
            String ip = IPUtils.getIpAddr(request);
            // 开源 https://github.com/lionsoul2014/ip2region
            IpInfo ipInfo = ip2regionSearcher.memorySearch(ip);
            String address = "UNKNOWN";
            if(ipInfo != null){
                address = ipInfo.getAddress();
            }

            // 暂时记录参数
//        Object[] args = pjp.getArgs();
//        String params = JSONObject.toJSONString(args);

            // 记录日志
            log.setOperationName(operationName);
            log.setUserName(username);
//        log.setParams(params);
            log.setSpendTime((int) time);
            log.setIp(ip);
            log.setIpSource(address);
            log.setUrl(operationUrl);
            log.setType(type);
        }else{
            // 记录日志
            log.setOperationName(operationName);
            log.setUserName("系统定时任务");
//        log.setParams(params);
            log.setSpendTime((int) time);
        }

        operationLogService.save(log);
    }
}
